package io.hepu.robotize.util;

import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Optional;

public class Clazz {

    public static <T> T cast(Object o, Class<T> clazz) {
        return clazz.isInstance(o) ? clazz.cast(o) : null;
    }

    public static <K, V> Map<K, V> cast(Object obj, Class<K> kClass, Class<V> vClass) {
        Map<K, V> result = new HashMap<>();
        if (obj instanceof Map) {
            Map cast = Clazz.cast(obj, Map.class);
            Iterator<?> iterator = Optional.ofNullable(cast).orElseGet(HashMap::new).entrySet().iterator();
            while (iterator.hasNext()) {
                Map.Entry next = (Map.Entry) iterator.next();
                result.put(kClass.cast(next.getKey()), vClass.cast(next.getValue()));
            }
            return result;
        }
        return null;
    }

    static public ParameterizedType getParameterizedType(Class<?> target) {
        Type[] types = getGenericType(target);
        if (types.length > 0 && types[0] instanceof ParameterizedType) {
            return (ParameterizedType) types[0];
        }
        return null;
    }

    static public Type[] getParameterizedTypes(Class<?> target) {
        Type[] types = getGenericType(target);
        if (types.length > 0 && types[0] instanceof ParameterizedType) {
            return ((ParameterizedType) types[0]).getActualTypeArguments();
        }
        return null;
    }

    static public Type[] getGenericType(Class<?> target) {
        if (target == null) {
            return new Type[0];
        }
        Type[] types = target.getGenericInterfaces();
        if (types.length > 0) {
            return types;
        }
        Type type = target.getGenericSuperclass();
        if (type != null) {
            if (type instanceof ParameterizedType) {
                return new Type[]{type};
            }
        }
        return new Type[0];
    }


    public static String name(Object obj) {
        return obj.getClass().getName();
    }
}
